package com.wanjia.estate.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.wanjia.estate.constant.Yhzgx;
import com.wanjia.estate.exception.ControllerException;
import com.wanjia.estate.exception.JmhxxSearchException;
import com.wanjia.estate.exception.PaperDoorException;
import com.wanjia.estate.mapper.EstateLogMapper;
import com.wanjia.estate.mapper.YtMapper;
import com.wanjia.estate.pojo.entity.Details;
import com.wanjia.estate.pojo.entity.EstateLog;
import com.wanjia.estate.pojo.entity.HomeInfoDetail;
import com.wanjia.estate.pojo.httpservice.Hydjxxhygr;
import com.wanjia.estate.pojo.httpservice.Hyxxchx;
import com.wanjia.estate.pojo.httpservice.Jmhxx;
import com.wanjia.estate.pojo.httpservice.Mzbhydjxx;
import com.wanjia.estate.pojo.model.JsonResult;
import com.wanjia.estate.pojo.print.PaperDrive;
import com.wanjia.estate.pojo.print.PrintInfo;
import com.wanjia.estate.properties.FolderPathProperties;
import com.wanjia.estate.properties.LinuxPdfProperties;
import com.wanjia.estate.properties.LinuxPrintProperties;
import com.wanjia.estate.service.CompressFolderService;
import com.wanjia.estate.service.PrintInfoService;
import com.wanjia.estate.service.bdservice.bdcdjxxcxjgzmservice.EnquiryOfMinorsService;
import com.wanjia.estate.service.httpservice.BdcHyZkHttpService;
import com.wanjia.estate.service.httpservice.NewPrintHttpService;
import com.wanjia.estate.service.httpservice.PrintHttpService;
import com.wanjia.estate.utils.FolderUtil;
import com.wanjia.estate.utils.LinuxPrintUtil;
import com.wanjia.estate.utils.LinuxUtil;
import com.wanjia.estate.utils.ThreadUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("/other")
@Tag(name = "其他接口控制器")
@Slf4j
public class OtherController extends BaseController {

    @Autowired
    CompressFolderService compressFolderService;

    @Autowired
    YtMapper mapper;

    @Setter(onMethod_ = @Autowired)
    private PrintHttpService service;

    @Autowired
    LinuxPrintProperties linuxPrintProperties;

    @Autowired
    LinuxPdfProperties linuxPdfProperties;

    @Autowired
    private FolderPathProperties folderPathProperties;

    @Setter(onMethod_ = @Autowired)
    private BdcHyZkHttpService bdcHyZkHttpService;

    @Setter(onMethod_ = @Autowired)
    private PrintInfoService printInfoService;

    @Autowired
    EnquiryOfMinorsService enquiryOfMinorsService;

    @Autowired
    EstateLogMapper estateLogMapper;

    @Setter(onMethod_ = @Autowired)
    private NewPrintHttpService newService;


    @Operation(summary = "完成所有手续的打包压缩信息接口")
    @PostMapping("/filesZip")
    public JsonResult<Object> fileZip() throws Exception {
        File folder = new File(folderPathProperties.getZippath());
        if (!folder.exists()) {
            folder.mkdir();
        }
        String sourceFolder = folderPathProperties.getPdfpath();
        String zipFileName = folderPathProperties.getZippath() + File.separator + ThreadUtil.getSlbh() + ".zip";

        // 创建输出流将压缩数据写入到zip文件中
        FileOutputStream fos = new FileOutputStream(zipFileName);
        ZipOutputStream zos = new ZipOutputStream(fos);

        // 将源文件夹下的所有文件压缩到zip文件中
        File srcFile = new File(sourceFolder);
        compressFolderService.compressFolder(srcFile, zos, "");

        // 关闭输出流
        zos.close();
        fos.close();

        return new JsonResult<>(OK);
    }

    @Operation(summary = "完成所有手续后删除图片文件夹的接口")
    @PostMapping("/rmImgFiles")
    public JsonResult<Object> rmImgFiles(){
        File folder=new File(folderPathProperties.getPdfpath());
        if (!folder.exists()) {
            folder.mkdir();
        }
        FolderUtil.deleteFolder(folder);
        log.info("图片信息文件夹删除");
        return new JsonResult<>(OK);
    }

    @Operation(summary = "随机生成业务编号")
    @GetMapping("/randomNum")
    public JsonResult<Object> randomNum(@Parameter(description = "受理机编号") String slj) {
        String randomNum = slj + System.currentTimeMillis();
        return new JsonResult<>(OK, randomNum);
    }

    @Operation(summary = "查住宅")
    @GetMapping("/Hsusage")
    public JsonResult<Integer> get(String name) {
        Integer uid = mapper.getHsusage(name);
        return new JsonResult<>(OK, uid);
//        return new JsonResult<>(OK, 0);
    }

    @Operation(summary = "判断权利人是否为父母未成年子女结构")
    @PostMapping("/checkHkb")
    public JsonResult<Boolean> checkHkb(@RequestBody List<Details> details) {
        if (CollUtil.isEmpty(details)) {
            throw new ControllerException("权利人不能为空");
        }
        if (details.size() == 1) {
            // 权利人唯一时，不需要判断
            return new JsonResult<>(OK, true);
        }

        if(details.size() == 2){
//            //权利人唯二时，判断是否结婚
//            for (Details detail : details) {
//                //查询配偶身份证
//                Details another = getAnother(detail);
//                if (detail.getIdcardno().equals(another.getIdcardno())){
//                    return new JsonResult<>(OK, true);
//                }
//            }
            String idcard=null;
            for (Details detail : details) {
                Details another = getAnother(detail);
                idcard=another.getIdcardno();
            }

            for (Details detail : details) {
                String idcardno = detail.getIdcardno();
                if (idcard.equals(idcardno)){
                    return new JsonResult<>(OK,true);
                }
            }
        }

        List<String> idList = details.stream()
                .filter(Objects::nonNull)
                .map(Details::getIdcardno)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());


        // 查询所有权利人的户口簿信息
        Jmhxx.Request request = new Jmhxx.Request();
        request.setData(idList.stream()
                .map(Jmhxx.RequestData::new)
                .collect(Collectors.toList()));
        Jmhxx.Response response = bdcHyZkHttpService.jmhxx(request);
        List<Jmhxx.Result> results = Optional.ofNullable(response)
                .filter(Jmhxx.Response::isSuccessful)
                .map(Jmhxx.Response::getData)
                .filter(Jmhxx.ResponseData::isSuccessful)
                .map(Jmhxx.ResponseData::getHcyXx)
                .map(Jmhxx.HcyXx::getResults)
                .orElse(null);
        if (CollUtil.isEmpty(results)) {
            throw new JmhxxSearchException("居民户信息查询失败");
        }

        // 查询到户主不唯一时，直接判定失败
        long hzCount = results.stream()
                .filter(r -> Objects.equals(r.getYhzgx(), Yhzgx.GX02.code()))
                .map(Jmhxx.Result::getGmsfhm)
                .distinct()
                .count();
        if (hzCount != 1) {
            return new JsonResult<>(OK, false);
        }

        // 汇总权利人关系与年龄
        Set<String> set = new HashSet<>();
        Map<Jmhxx.Result, Yhzgx> gxMap = new HashMap<>();
        Map<Jmhxx.Result, Integer> ageMap = new HashMap<>();
        results.stream()
                .filter(r -> idList.contains(r.getGmsfhm()))
                .forEach(r -> {
                    String sf = r.getGmsfhm();
                    if (!set.contains(sf)) {
                        Yhzgx y = Yhzgx.get(r.getYhzgx());
                        Integer age = r.calculateYear();
                        gxMap.put(r, y);
                        ageMap.put(r, age);
                        set.add(sf);
                    }
                });

        // 循环校验权利人
        boolean isChecked = false;
        for (Yhzgx y : gxMap.values()) {

            // 父母校验
            if (Yhzgx.PARENT.contains(y)) {
                isChecked = true;
                // 校验非户主/父母以及兄弟姐妹
                Jmhxx.Result r0 = gxMap.entrySet()
                        .stream()
                        .filter(e -> {
                            Jmhxx.Result r = e.getKey();
                            Yhzgx gx = e.getValue();
                            Integer age = ageMap.get(r);
                            if (!Objects.equals(gx, Yhzgx.GX02) && !Yhzgx.PARENT.contains(gx) && !Yhzgx.BROTHER_AND_SISTER.contains(gx)) {
                                return true;
                            }

                            if (Objects.equals(gx, Yhzgx.GX02) || Yhzgx.BROTHER_AND_SISTER.contains(gx)) {
                                return age >= 18;
                            }

                            return false;
                        })
                        .findAny()
                        .map(Map.Entry::getKey)
                        .orElse(null);
                if (r0 != null) {
                    log.debug("[{}]未通过父母校验", r0.getXm());
                    return new JsonResult<>(OK, false);
                }
            }

            // 配偶校验
            if (Yhzgx.PARENT.contains(y)) {
                isChecked = true;
                // 校验非户主/配偶以及子女
                Jmhxx.Result r0 = gxMap.entrySet()
                        .stream()
                        .filter(e -> {
                            Jmhxx.Result r = e.getKey();
                            Yhzgx gx = e.getValue();
                            Integer age = ageMap.get(r);
                            if (!Objects.equals(gx, Yhzgx.GX02) && !Yhzgx.SPOUSE.contains(gx) && !Yhzgx.CHILDREN.contains(gx)) {
                                return true;
                            }

                            if (Yhzgx.CHILDREN.contains(gx)) {
                                return age >= 18;
                            }

                            return false;
                        })
                        .findAny()
                        .map(Map.Entry::getKey)
                        .orElse(null);
                if (r0 != null) {
                    log.debug("[{}]未通过配偶校验", r0.getXm());
                    return new JsonResult<>(OK, false);
                }
            }

            // 子女校验
            if (Yhzgx.CHILDREN.contains(y)) {
                isChecked = true;
                // 校验非户主/夫妻以及子女
                Jmhxx.Result r0 = gxMap.entrySet()
                        .stream()
                        .filter(e -> {
                            Jmhxx.Result r = e.getKey();
                            Yhzgx gx = e.getValue();
                            Integer age = ageMap.get(r);
                            if (!Objects.equals(gx, Yhzgx.GX02) && !Yhzgx.SPOUSE.contains(gx) && !Yhzgx.CHILDREN.contains(gx)) {
                                return true;
                            }

                            if (Yhzgx.CHILDREN.contains(gx)) {
                                return age >= 18;
                            }

                            return false;
                        })
                        .findAny()
                        .map(Map.Entry::getKey)
                        .orElse(null);
                if (r0 != null) {
                    log.debug("[{}]未通过子女校验", r0.getXm());
                    return new JsonResult<>(OK, false);
                }
            }

            // 兄弟姐妹校验
            if (Yhzgx.BROTHER_AND_SISTER.contains(y)) {
                isChecked = true;
                // 校验非户主/父母以及兄弟姐妹
                Jmhxx.Result r0 = gxMap.entrySet()
                        .stream()
                        .filter(e -> {
                            Jmhxx.Result r = e.getKey();
                            Yhzgx gx = e.getValue();
                            Integer age = ageMap.get(r);
                            if (!Objects.equals(gx, Yhzgx.GX02) && !Yhzgx.PARENT.contains(gx) && !Yhzgx.BROTHER_AND_SISTER.contains(gx)) {
                                return true;
                            }

                            if (Objects.equals(gx, Yhzgx.GX02) || Yhzgx.BROTHER_AND_SISTER.contains(gx)) {
                                return age >= 18;
                            }

                            return false;
                        })
                        .findAny()
                        .map(Map.Entry::getKey)
                        .orElse(null);
                if (r0 != null) {
                    log.debug("[{}]未通过兄弟姐妹校验", r0.getXm());
                    return new JsonResult<>(OK, false);
                }
            }
        }
        if (!isChecked) {
            // 所有校验未被触发，则判定失败
            return new JsonResult<>(OK, false);
        }

        // 通过所有校验则判定成功
        return new JsonResult<>(OK, true);
    }


    @Operation(summary = "判断权利人婚姻状况")
    @PostMapping("/checkHy")
    public JsonResult<List<List<Details>>> checkHy(@RequestBody List<Details> details) {
        // 准备数据
        Set<String> checked = new HashSet<>();
        Map<String, List<Details>> map = new HashMap<>();
        List<List<Details>> result = new ArrayList<>();

        // 遍历判断权利人
        details.forEach(detail -> {
            String idcardno = detail.getIdcardno();

            if (checked.contains(idcardno)) {
                // 已经登记过身份证号的权利人，直接加入集合
                map.get(idcardno).add(detail);
            } else {
                Details another = getAnother(detail);
                if (another == null) {
                    // 未找到有效结婚信息，直接开始下一个人
                    return;
                }

                // 全部婚姻信息登记
                checked.add(idcardno);
                List<Details> list = CollUtil.newArrayList(detail);
                result.add(list);
                map.put(idcardno, list);
                map.put(another.getIdcardno(), list);
            }
        });

        return new JsonResult<>(OK, result);
    }

    private Details getAnother(Details detail) {
        String name = detail.getName();
        String idcardno = detail.getIdcardno();
        Details another = null;

        // 校验是否离婚/婚姻登记个人
        Hydjxxhygr.Request request = new Hydjxxhygr.Request();
        Hydjxxhygr.RequestData data = new Hydjxxhygr.RequestData();
        data.setCert_num_man(idcardno);
        data.setName_man(name);
        request.setData(CollUtil.newArrayList(data));

        Hydjxxhygr.Response response = bdcHyZkHttpService.hydjxxhygr(request);
        String result = Optional.ofNullable(response)
                .map(Hydjxxhygr.Response::getData)
                .map(Hydjxxhygr.ResponseData::getResult)
                .orElse(null);

        if (result != null && (result.startsWith("IB:") || result.startsWith("ICB:"))) {
            return null;
        }

        // 省民政厅接口
        Hyxxchx.Request request1 = new Hyxxchx.Request();
        Hyxxchx.RequestData data1 = new Hyxxchx.RequestData();
        request1.setData(CollUtil.newArrayList(data1));
        data1.setCertNum(idcardno);
        data1.setClientName("HY");

        Hyxxchx.Response response1 = bdcHyZkHttpService.hyxxchx(request1);
        another = Optional.ofNullable(response1)
                .map(Hyxxchx.Response::getData)
                .orElseGet(ArrayList::new)
                .stream()
                .filter(row -> Objects.equals(row.getOpType(), "IA"))
                .findAny()
                .map(d -> new Details(d.getSpouseCertNum(), d.getSpouseName()))
                .orElse(null);
        if (another != null) {
            return another;
        }

        // 婚姻登记信息核验
        Mzbhydjxx.Request request2 = new Mzbhydjxx.Request();
        Mzbhydjxx.RequestData requestData2 = new Mzbhydjxx.RequestData();
        requestData2.setName(name);
        requestData2.setCert_num(idcardno);
        request2.setData(CollUtil.newArrayList(requestData2));
        Mzbhydjxx.Response response2 = bdcHyZkHttpService.mzbhydjxx(request2);

        another = Optional.of(response2)
                .map(Mzbhydjxx.Response::getData)
                .map(Mzbhydjxx.ResponseData::getRows)
                .orElseGet(ArrayList::new)
                .stream()
                .filter(row -> Objects.equals(row.getOp_type(), "IA") &&
                        (Objects.equals(idcardno, row.getCert_num_man()) ||
                                Objects.equals(idcardno, row.getCert_num_woman())))
                .map(d -> {
                    if (Objects.equals(idcardno, d.getCert_num_man())) {
                        return new Details(d.getCert_num_woman(), d.getName_woman());
                    } else {
                        return new Details(d.getCert_num_man(), d.getName_man());
                    }
                })
                .findAny()
                .orElse(null);
        if (another != null) {
            return another;
        }

        // 查询户口簿
        Jmhxx.Request request3 = new Jmhxx.Request();
        request3.setData(CollUtil.newArrayList(new Jmhxx.RequestData(idcardno)));
        Jmhxx.Response response3 = bdcHyZkHttpService.jmhxx(request3);
        List<Jmhxx.Result> results = Optional.ofNullable(response3)
                .map(Jmhxx.Response::getData)
                .map(Jmhxx.ResponseData::getHcyXx)
                .map(Jmhxx.HcyXx::getResults)
                .orElseGet(ArrayList::new);
        Jmhxx.Result detailResult = results.stream()
                .filter(r -> Objects.equals(r.getGmsfhm(), idcardno))
                .findFirst()
                .orElse(null);
        if (detailResult != null) {
            if (Objects.equals(detailResult.getYhzgx(), Yhzgx.GX02.code())) {
                another = results.stream()
                        .filter(r -> Yhzgx.SPOUSE_CODE.contains(r.getYhzgx()))
                        .findFirst()
                        .map(r -> new Details(r.getGmsfhm(), r.getXm()))
                        .orElse(null);
            }

            if (Yhzgx.SPOUSE_CODE.contains(detailResult.getYhzgx())) {
                another = results.stream()
                        .filter(r -> Objects.equals(r.getYhzgx(), Yhzgx.GX02.code()))
                        .findFirst()
                        .map(r -> new Details(r.getGmsfhm(), r.getXm()))
                        .orElse(null);
            }
        }

        return another;
    }


    @Operation(summary = "打印接口")
    @PostMapping("/printOK")
    public JsonResult<Object> printOK(String fileName,
                                      @RequestParam(required = false) Integer count) throws InterruptedException {
        if (count == null) {
            count = 1;
        }

        newService.PaperDrive();
        Thread.sleep(5000L);
        for (int i = 0; i < count; i++) {
            LinuxPrintUtil.linuxPrint(linuxPrintProperties.getPrintprefix(), fileName, linuxPrintProperties.getPrintername(), linuxPrintProperties.getPrintsuffix1());
            Thread.sleep(10000L);
        }
        Thread.sleep(5000L);
        newService.PaperStop();
        Thread.sleep(5000L);
        newService.newRepeatOpenPaperDoor();
        return new JsonResult<>(OK);
    }

    @Operation(summary = "查询打印机信息")
    @GetMapping("/print/info")
    public JsonResult<PrintInfo.Response> printInfo() {
        PrintInfo.Response info = printInfoService.info();
        return new JsonResult<>(OK, info);
    }

    @Operation(summary = "查询家庭关系列表")
    @PostMapping ("/home/relationship")
    public JsonResult<HomeInfoDetail> adultRelationship(@RequestBody Details detail) {
        Integer integer = detail.calculateYear();
        if (integer>=18){
            HomeInfoDetail homeInfoDetail = getHomeInfoDetail(detail);
            return new JsonResult<>(OK, homeInfoDetail);
        }
        HomeInfoDetail infoDetail = getInfoDetail(detail);
        return new JsonResult<>(OK, infoDetail);
    }


    //成年人查询家庭关系列表
    private HomeInfoDetail getHomeInfoDetail(Details detail) {
        HomeInfoDetail homeInfoDetail = new HomeInfoDetail();
        List<Details> adultDetail=new ArrayList<>();
        Details another = getAnother(detail);
        List<Details> details = new ArrayList<>();
        List<Details> detail1 = enquiryOfMinorsService.getChildren(detail);
        if (another!=null){
            adultDetail.add(another);
            List<Details> detail2 = enquiryOfMinorsService.getChildren(another);
            details.addAll(detail2);
        }
        details.addAll(detail1);
//        details = CollUtil.distinct(details);
//        details = new ArrayList<>(new LinkedHashSet<>(details));
        details = details.stream().distinct().collect(Collectors.toList());
        homeInfoDetail.setAdult(adultDetail);
        homeInfoDetail.setChildren(details);
        return homeInfoDetail;
    }


//    @Operation(summary = "未成年人查询家庭关系列表")
//    @PostMapping ("/home/minor/relationship")
//    public JsonResult<HomeInfoDetail> minorRelationship(@RequestBody Details detail) {
//        HomeInfoDetail homeInfoDetail = getInfoDetail(detail);
//        return new JsonResult<>(OK, homeInfoDetail);
//    }

    //未成年人查询家庭关系列表
    private HomeInfoDetail getInfoDetail(Details detail) {
        HomeInfoDetail homeInfoDetail = new HomeInfoDetail();
        List<Details> childrenDetail=new ArrayList<>();

        List<Details> adults = enquiryOfMinorsService.getAdults(detail);
        List<Details> adultAnother = new ArrayList<>();
        if (!adults.isEmpty()) {
            for (Details adult : adults) {
                Details another = getAnother(adult);
                if (another!=null){
                    adultAnother.add(another);
                }
            }
        }
        List<Details> details = new ArrayList<>();
        details.addAll(adults);
        details.addAll(adultAnother);
        details = details.stream().distinct().collect(Collectors.toList());

        for (Details detail1 : details) {
            List<Details> children = enquiryOfMinorsService.getChildren(detail1);
            childrenDetail.addAll(children);
        }

        childrenDetail=childrenDetail.stream()
                .distinct()
                .filter(r->!Objects.equals(r.getIdcardno(),detail.getIdcardno()))
                .collect(Collectors.toList());

        homeInfoDetail.setAdult(details);
        homeInfoDetail.setChildren(childrenDetail);
        return homeInfoDetail;
    }


    @Operation(summary = "两人夫妻关系判断")
    @PostMapping ("/home/marriage/relationship")
    public JsonResult<Boolean> marriageRelationship(@RequestBody List<Details> detail) {
        String idcard=null;
        for (Details details : detail) {
            Details another = getAnother(details);
            if (another==null||another.getIdcardno().isEmpty()){
                return new JsonResult<>(OK,false);
            }
            idcard=another.getIdcardno();
        }

        for (Details details : detail) {
            String idcardno = details.getIdcardno();
            if (idcard.equals(idcardno)){
                return new JsonResult<>(OK,true);
            }
        }

        return new JsonResult<>(OK,false);
    }

    @Operation(summary = "单人婚姻判断")
    @PostMapping ("/home/marriageOne/relationship")
    public JsonResult<Boolean> oneMarriageRelationship(@RequestBody Details detail) {
        Details another = getAnother(detail);
        if (another==null||another.getIdcardno().isEmpty()){
            return new JsonResult<>(OK,false);
        }
        return new JsonResult<>(OK,true);
    }

    @Operation(summary = "传文件")
    @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String upload(@RequestPart MultipartFile file) throws IOException {
        File localFile = new File("/home/wanjia/estate/upload/"+file.getOriginalFilename());
        FileUtil.mkParentDirs(localFile);
        FileUtil.writeFromStream(file.getInputStream(), localFile);
        return "ok";
    }

    @Operation(summary = "传日志")
    @PostMapping("/estate/log")
    public JsonResult<Integer> addLogs(@RequestBody EstateLog estateLog){
        estateLog.setJysj(new Date());
        int i = estateLogMapper.addLog(estateLog);
        return new JsonResult<>(OK,i);
    }

    @GetMapping("/test/log")
    public JsonResult<JSONObject> testlog(){
//        log.debug("debug success!");
//        log.warn("warn success!");
//        log.info("info success!");
//        log.error("error success!");
        JSONObject dataTc = new JSONObject();
        dataTc.set("debug","debug success!");
        dataTc.set("warn","warn success!");
        dataTc.set("info","info success!");
        dataTc.set("error","error success!");
        return new JsonResult<>(OK,dataTc);
    }

    @PostMapping("/test/file")
    public String testfile(String cmd){
        LinuxUtil.LinuxPdf(cmd);
        return "ok";
    }
}
